﻿Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Configuration
Imports System.Globalization
Imports System.Reflection
Imports System.Workflow.ComponentModel.Compiler

Namespace System.Workflow.ComponentModel
    Friend MustInherit Class MemberBind
        Inherits BindBase
        ' Methods
        Protected Sub New()
            Me.name = String.Empty
        End Sub

        Protected Sub New(ByVal name As String)
            Me.name = String.Empty
            Me.name = name
        End Sub

        Friend Shared Function GetMemberInfo(ByVal srcType As Type, ByVal path As String) As MemberInfo
            Dim walker As PathWalker
            If (srcType Is Nothing) Then
                Throw New ArgumentNullException("srcType")
            End If
            If (path Is Nothing) Then
                Throw New ArgumentNullException("path")
            End If
            If (path.Length = 0) Then
                Throw New ArgumentException(SR.GetString("Error_EmptyPathValue"), "path")
            End If
            Dim rootType As Type = srcType
            Dim memberInfo As MemberInfo = Nothing
            If New PathWalker() { _
                .MemberFound = DirectCast(Delegate.Combine(walker.MemberFound, Function (ByVal sender As Object, ByVal eventArgs As PathMemberInfoEventArgs) 
                    memberInfo = eventArgs.MemberInfo
                    If (eventArgs.MemberKind = PathMemberKind.Event) Then
                        eventArgs.Action = PathWalkAction.Stop
                    End If
                End Function), EventHandler([Of] PathMemberInfoEventArgs)) _
            }.TryWalkPropertyPath(rootType, path) Then
                Return memberInfo
            End If
            Return Nothing
        End Function

        Friend Shared Function GetValue(ByVal memberInfo As MemberInfo, ByVal dataContext As Object, ByVal path As String) As Object
            Dim walker As PathWalker
            If (memberInfo Is Nothing) Then
                Throw New ArgumentNullException("memberInfo")
            End If
            If (dataContext Is Nothing) Then
                Throw New ArgumentNullException("dataContext")
            End If
            If (path Is Nothing) Then
                path = String.Empty
            End If
            If String.IsNullOrEmpty(path) Then
                Return Nothing
            End If
            Dim targetObject As Object = dataContext
            Dim memberType As Type = dataContext.GetType
            If Not New PathWalker() { _
                .MemberFound = DirectCast(Delegate.Combine(walker.MemberFound, Function (ByVal sender As Object, ByVal eventArgs As PathMemberInfoEventArgs) 
                    If (targetObject Is Nothing) Then
                        eventArgs.Action = PathWalkAction.Cancel
                        Return
                    End If
                    Select Case eventArgs.MemberKind
                        Case PathMemberKind.Field
                            memberType = [TryCast](eventArgs.MemberInfo,FieldInfo).FieldType
                            targetObject = [TryCast](eventArgs.MemberInfo,FieldInfo).GetValue(targetObject)
                            goto Label_01CC
                        Case PathMemberKind.Event
                            Dim memberInfo As EventInfo = [TryCast](eventArgs.MemberInfo,EventInfo)
                            memberType = memberInfo.EventHandlerType
                            Dim obj1 As DependencyObject = [TryCast](targetObject,DependencyObject)
                            Dim dependencyProperty As DependencyProperty = DependencyProperty.FromName(memberInfo.Name, obj1.GetType)
                            If ((dependencyProperty Is Nothing) OrElse (obj1 Is Nothing)) Then
                                targetObject = Nothing
                                Exit Select
                            End If
                            If Not obj1.IsBindingSet(dependencyProperty) Then
                                targetObject = obj1.GetHandler(dependencyProperty)
                                Exit Select
                            End If
                            targetObject = obj1.GetBinding(dependencyProperty)
                            Exit Select
                        Case PathMemberKind.Property
                            memberType = [TryCast](eventArgs.MemberInfo,PropertyInfo).PropertyType
                            If [TryCast](eventArgs.MemberInfo,PropertyInfo).CanRead Then
                                targetObject = [TryCast](eventArgs.MemberInfo,PropertyInfo).GetValue(targetObject, Nothing)
                                goto Label_01CC
                            End If
                            eventArgs.Action = PathWalkAction.Cancel
                            Return
                        Case PathMemberKind.IndexedProperty
                            memberType = [TryCast](eventArgs.MemberInfo,PropertyInfo).PropertyType
                            If [TryCast](eventArgs.MemberInfo,PropertyInfo).CanRead Then
                                targetObject = [TryCast](eventArgs.MemberInfo,PropertyInfo).GetValue(targetObject, eventArgs.IndexParameters)
                                goto Label_01CC
                            End If
                            eventArgs.Action = PathWalkAction.Cancel
                            Return
                        Case PathMemberKind.Index
                            memberType = [TryCast](eventArgs.MemberInfo,PropertyInfo).PropertyType
                            targetObject = [TryCast](eventArgs.MemberInfo,PropertyInfo).GetValue(targetObject, BindingFlags.GetProperty, Nothing, eventArgs.IndexParameters, CultureInfo.InvariantCulture)
                            goto Label_01CC
                        Case Else
                            goto Label_01CC
                    End Select
                    eventArgs.Action = PathWalkAction.Stop
                Label_01CC:
                    If (Not targetObject Is Nothing) Then
                        Return
                    End If
                    If Not eventArgs.LastMemberInThePath Then
                        Throw New InvalidOperationException(SR.GetString("Error_BindPathNullValue", New Object() { eventArgs.Path }))
                    End If
                    eventArgs.Action = PathWalkAction.Cancel
                End Function), EventHandler([Of] PathMemberInfoEventArgs)) _
            }.TryWalkPropertyPath(memberType, path) Then
                Return Nothing
            End If
            If (targetObject Is dataContext) Then
                Return Nothing
            End If
            Return targetObject
        End Function

        Private Shared Function SafeType(ByVal authorizedTypes As List([Of] AuthorizedType), ByVal referenceType As Type) As Boolean
            Dim flag As Boolean = False
            Dim type As AuthorizedType
            For Each type In authorizedTypes
                If type.RegularExpression.IsMatch(referenceType.AssemblyQualifiedName) Then
                    flag = (String.Compare(Boolean.TrueString, type.Authorized, StringComparison.OrdinalIgnoreCase) = 0)
                    If Not flag Then
                        Return False
                    End If
                End If
            Next
            Return flag
        End Function

        Friend Shared Sub SetValue(ByVal dataContext As Object, ByVal path As String, ByVal value As Object)
            Dim walker As PathWalker
            If (dataContext Is Nothing) Then
                Throw New ArgumentNullException("dataContext")
            End If
            If String.IsNullOrEmpty(path) Then
                Throw New ArgumentNullException("path")
            End If
            Dim parentObj As Object = Nothing
            Dim obj As Object = dataContext
            Dim args As Object() = Nothing
            Dim memberInfo As MemberInfo = Nothing
            If New PathWalker() { _
                .MemberFound = DirectCast(Delegate.Combine(walker.MemberFound, Function (ByVal sender As Object, ByVal eventArgs As PathMemberInfoEventArgs) 
                    If (obj Is Nothing) Then
                        eventArgs.Action = PathWalkAction.Cancel
                    Else
                        parentObj = obj
                        memberInfo = eventArgs.MemberInfo
                        Select Case eventArgs.MemberKind
                            Case PathMemberKind.Field
                                obj = [TryCast](eventArgs.MemberInfo,FieldInfo).GetValue(parentObj)
                                args = Nothing
                                Return
                            Case PathMemberKind.Event
                                eventArgs.Action = PathWalkAction.Cancel
                                Return
                            Case PathMemberKind.Property
                                obj = [TryCast](eventArgs.MemberInfo,PropertyInfo).GetValue(parentObj, Nothing)
                                args = Nothing
                                Return
                            Case PathMemberKind.IndexedProperty, PathMemberKind.Index
                                obj = [TryCast](eventArgs.MemberInfo,PropertyInfo).GetValue(parentObj, eventArgs.IndexParameters)
                                args = eventArgs.IndexParameters
                                Return
                        End Select
                    End If
                End Function), EventHandler([Of] PathMemberInfoEventArgs)) _
            }.TryWalkPropertyPath(dataContext.GetType, path) Then
                If TypeOf memberInfo Is FieldInfo Then
                    [TryCast](memberInfo,FieldInfo).SetValue(parentObj, value)
                ElseIf TypeOf memberInfo Is PropertyInfo Then
                    If Not [TryCast](memberInfo,PropertyInfo).CanWrite Then
                        Throw New InvalidOperationException(SR.GetString("Error_ReadOnlyField", New Object() { memberInfo.Name }))
                    End If
                    [TryCast](memberInfo,PropertyInfo).SetValue(parentObj, value, args)
                End If
            End If
        End Sub

        Friend Shared Function ValidateTypesInPath(ByVal srcType As Type, ByVal path As String) As ValidationError
            Dim walker As PathWalker
            Dim error As ValidationError = Nothing
            If (srcType Is Nothing) Then
                Throw New ArgumentNullException("srcType")
            End If
            If (path Is Nothing) Then
                Throw New ArgumentNullException("path")
            End If
            If (path.Length = 0) Then
                Throw New ArgumentException(SR.GetString("Error_EmptyPathValue"), "path")
            End If
            Dim authorizedTypes As List([Of] AuthorizedType) = Nothing
            Try 
                authorizedTypes = [TryCast](ConfigurationManager.GetSection("System.Workflow.ComponentModel.WorkflowCompiler/authorizedTypes"),List([Of] AuthorizedType))
            Catch obj1 As Object
            End Try
            If (authorizedTypes Is Nothing) Then
                Return New ValidationError(SR.GetString("Error_ConfigFileMissingOrInvalid"), &H178)
            End If
            Dim rootType As Type = srcType
            Dim memberInfo As MemberInfo = Nothing
            New PathWalker() { _
                .MemberFound = DirectCast(Delegate.Combine(walker.MemberFound, Function (ByVal sender As Object, ByVal eventArgs As PathMemberInfoEventArgs) 
                    Dim fieldType As Type = Nothing
                    memberInfo = eventArgs.MemberInfo
                    If TypeOf memberInfo Is FieldInfo Then
                        fieldType = DirectCast(memberInfo, FieldInfo).FieldType
                    End If
                    If TypeOf memberInfo Is PropertyInfo Then
                        fieldType = DirectCast(memberInfo, PropertyInfo).PropertyType
                    End If
                    If ((Not fieldType Is Nothing) AndAlso Not MemberBind.SafeType(authorizedTypes, fieldType)) Then
                        [error] = New ValidationError(SR.GetString("Error_TypeNotAuthorized", New Object() { fieldType }), &H16B)
                        eventArgs.Action = PathWalkAction.Stop
                    End If
                End Function), EventHandler([Of] PathMemberInfoEventArgs)) _
            }.TryWalkPropertyPath(rootType, path)
            Return [error]
        End Function


        ' Properties
        <DefaultValue("")> _
        Public ReadOnly Property Name As String
            Get
                Return Me.name
            End Get
        End Property


        ' Fields
        Private name As String
    End Class
End Namespace

